/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-11-27     AlgoIdeas       the first version
 */

#include <rtthread.h>
#include <rtdevice.h>

// #define DRV_DEBUG
#define DBG_TAG "app.key"
#include <rtdbg.h>

#include "key.h"


/** key information */
typedef struct _key_info
{
    key_code_t code;
    key_state_t state;
    rt_bool_t short_press_done;
    rt_bool_t short_press;
    rt_bool_t long_press_done;
    rt_bool_t long_press;
    rt_bool_t double_press_done;
    rt_bool_t double_press;
    rt_uint32_t timtick;
    rt_uint32_t double_timtick;
} key_info_t;

static key_info_t key_info[KEY_CODE_MAX];
static rt_uint8_t key_s2, key_s3;
static key_callback_t key_callback = RT_NULL;

/**
 * @brief  key event check for short click and hold mode
 * @param[in]enKeyType : key type index
 * @param[in/out]info : keymng information
 * @return NA
 */
static void key_hold_check(key_info_t *info)
{
    /* Time tick count */
    info->timtick ++;
    info->double_timtick ++;

    if ((KEY_STATE_DOWN == info->state))
    {
        if (RT_FALSE == info->short_press_done)
        {
            info->short_press_done = RT_TRUE;
            info->timtick = 0;
        }
        else if (RT_TRUE == info->short_press_done)
        {
            if (info->timtick > (KEY_LONG_PRESS_TIME / KEY_CHECK_INTERVAL))
            {
                info->short_press_done = RT_FALSE;
                if (RT_TRUE != info->long_press)
                {
                    info->long_press = RT_TRUE;
                    rt_kprintf("Key Hold [%d]\n", info->code);

                    if (RT_NULL != key_callback) {
                        key_callback(info->code, KEY_EVT_HOLD);
                    }
                }
            }
        }
    }

    if ((KEY_STATE_UP == info->state))
    {
        if (RT_TRUE == info->short_press_done)
        {
            info->short_press_done = RT_FALSE;
            if (RT_FALSE == info->double_press_done)
            {
                info->double_press_done = RT_TRUE;
                info->double_timtick = 0;
            }
            else
            {
                if (info->double_timtick <  (KEY_DOUBLE_PRESS_TIME / KEY_CHECK_INTERVAL))
                {
                    info->double_press_done = RT_FALSE;
                    if (RT_TRUE == info->long_press)
                    {
                        info->long_press = RT_FALSE;
                    }

                    info->double_press = RT_TRUE;
                    rt_kprintf("Key Double [%d]\n", info->code);
                    if (RT_NULL != key_callback) {
                        key_callback(info->code, KEY_EVT_DOUBLE);
                    }
                }
            }
        }
        else if (RT_TRUE == info->double_press_done)
        {
            if (info->double_timtick > (KEY_SHORT_PRESS_TIME / KEY_CHECK_INTERVAL))
            {
                info->double_press_done = RT_FALSE;

                if (RT_TRUE == info->long_press)
                {
                    info->long_press = RT_FALSE;
                    info->short_press = RT_TRUE;
                }
                else
                {
                    info->short_press = RT_TRUE;
                    rt_kprintf("Key Down [%d]\n", info->code);
                    if (RT_NULL != key_callback) {
                        key_callback(info->code, KEY_EVT_DOWN);
                    }
                }
            }
        }
    }

    if ((KEY_STATE_UP == info->state))
    {
        if ((RT_TRUE == info->short_press) || (RT_TRUE == info->double_press))
        {
            info->short_press  = RT_FALSE;
            info->double_press = RT_FALSE;
            info->timtick = 0;
            info->double_timtick = 0;
            if (RT_NULL != key_callback) {
                key_callback(info->code, KEY_EVT_UP);
            }
        }
    }

    return ;
}

static void key_entry(void *parameter)
{
    while (1)
    {
        key_info[KEY_CODE_S2].state = rt_pin_read(key_s2);
        key_hold_check(&key_info[KEY_CODE_S2]);

        key_info[KEY_CODE_S3].state = rt_pin_read(key_s3);
        key_hold_check(&key_info[KEY_CODE_S3]);

        rt_thread_mdelay(10);
    }

    return ;
}

int key_init(key_callback_t callback)
{
    rt_thread_t tid;

    if (RT_NULL != callback) {
        key_callback = callback;
    }

    key_s2 = rt_pin_get("PF.1");
    key_s3 = rt_pin_get("PF.0");

    key_info[KEY_CODE_S2].code = KEY_CODE_S2;
    key_info[KEY_CODE_S2].state = KEY_STATE_UP;
    key_info[KEY_CODE_S3].code = KEY_CODE_S3;
    key_info[KEY_CODE_S3].state = KEY_STATE_UP;

    rt_pin_mode(key_s2, PIN_MODE_INPUT);
    rt_pin_mode(key_s3, PIN_MODE_INPUT);

    tid = rt_thread_create("key_init", key_entry,
            RT_NULL,
            4096,
            RT_THREAD_PRIORITY_MAX / 2,
            20);
    if (tid != RT_NULL)
    {
        rt_thread_startup(tid);
    }
    else
    {
        LOG_E("rt_thread_create key_init thread failed!");
        return RT_ERROR;
    }

    return 0;
}
